package io.kiki.sba.registry.common.model.metaserver.inter.heartbeat;


import io.kiki.sba.registry.common.model.metaserver.cluster.VersionedList;
import io.kiki.sba.registry.common.model.metaserver.nodes.CentralControlNode;
import io.kiki.sba.registry.common.model.metaserver.nodes.ClientInterfaceNode;
import io.kiki.sba.registry.common.model.multi.cluster.RemoteSlotsStatus;
import io.kiki.sba.registry.common.model.slot.Slots;
import lombok.Getter;
import lombok.Setter;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;

@Setter
@Getter
public class HeartBeatResponse implements Serializable {

    @Getter
    private final boolean heartbeatOnLeader;

    @Getter
    private final Slots slots;

    private final VersionedList<CentralControlNode> centralControlNodeVersionedList;

    private final VersionedList<ClientInterfaceNode> clientInterfaceNodeVersionedList;

    @Getter
    private final String metaLeader;

    @Getter
    private final long metaLeaderEpoch;

    @Getter
    private final Map<String, RemoteSlotsStatus> remoteSlotsStatusMap;

    public HeartBeatResponse(boolean heartbeatOnLeader, String metaLeader, long metaLeaderEpoch) {
        this(heartbeatOnLeader, null, null, metaLeader, metaLeaderEpoch);
    }

    public HeartBeatResponse(boolean heartbeatOnLeader, VersionedList<CentralControlNode> centralControlNodeVersionedList, Slots slots, String metaLeader, long metaLeaderEpoch) {
        this(heartbeatOnLeader, centralControlNodeVersionedList, slots, VersionedList.EMPTY, metaLeader, metaLeaderEpoch, Collections.emptyMap());
    }

    public HeartBeatResponse(boolean heartbeatOnLeader, VersionedList<CentralControlNode> centralControlNodeVersionedList, Slots slots, VersionedList<ClientInterfaceNode> clientInterfaceNodeVersionedList, String metaLeader, long metaLeaderEpoch, Map<String, RemoteSlotsStatus> remoteSlotsStatusMap) {
        this.heartbeatOnLeader = heartbeatOnLeader;
        this.slots = slots;
        this.centralControlNodeVersionedList = centralControlNodeVersionedList;
        this.clientInterfaceNodeVersionedList = clientInterfaceNodeVersionedList;
        this.metaLeader = metaLeader;
        this.metaLeaderEpoch = metaLeaderEpoch;
        this.remoteSlotsStatusMap = remoteSlotsStatusMap;
    }

    public Map<String, ClientInterfaceNode> getSessionNodesMap() {
        final Map<String, ClientInterfaceNode> map = new HashMap<>(clientInterfaceNodeVersionedList.getList().size());
        clientInterfaceNodeVersionedList.getList().forEach(clientInterfaceNode -> map.put(clientInterfaceNode.getIp(), clientInterfaceNode));
        return map;
    }

    public Set<String> getDataCentersFromMetaNodes() {
        Set<String> set = new HashSet<>();
        centralControlNodeVersionedList.getList().forEach(centralControlNode -> set.add(centralControlNode.getDataCenter()));
        return set;
    }

    public long getSessionServerEpoch() {
        return clientInterfaceNodeVersionedList.getEpoch();
    }


    public Map<String, Set<String>> getRemoteDataServers() {

        if (CollectionUtils.isEmpty(remoteSlotsStatusMap)) {
            return new HashMap<>();
        }

        Map<String, Set<String>> map = new HashMap<>(remoteSlotsStatusMap.size());
        for (Entry<String, RemoteSlotsStatus> entry : remoteSlotsStatusMap.entrySet()) {
            RemoteSlotsStatus remoteSlotsStatus = entry.getValue();
            if (remoteSlotsStatus != null && remoteSlotsStatus.isSlotsUpgrade() && remoteSlotsStatus.getSlots() != null) {
                map.put(entry.getKey(), remoteSlotsStatus.getSlots().getDataServers());
            }
        }
        return map;
    }
}
